package com.itheima.myreggie2.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.myreggie2.common.R;
import com.itheima.myreggie2.dto.DishDto;
import com.itheima.myreggie2.entity.Category;
import com.itheima.myreggie2.entity.Dish;
import com.itheima.myreggie2.entity.DishFlavor;
import com.itheima.myreggie2.service.ICategoryService;
import com.itheima.myreggie2.service.IDishFlavorService;
import com.itheima.myreggie2.service.IDishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 *  菜品管理
 */
@Slf4j
@RestController
@RequestMapping("/dish") //请求url地址：
public class DishController {

    @Autowired
    IDishService dishService;

    @Autowired
    IDishFlavorService dishFlavorService;

    @Autowired
    ICategoryService categoryService;

    /**    新增菜品功能开发
     *  接口1：查询菜品分类列表数据*
     *  请求url地址：/category/list ?type=1
     *  怎么又回到category类呢？因为在新增页面里有个菜品分类的查询展示框（菜品类查询和套餐类查询）
     *   因此将新增写到  categoryController 中
     */

    /**
     * ###### 添加菜品【复杂】
     * > 备注：涉及表 Dish【菜品表】、Dish_flavor【菜品口味表】
     * 请求url地址：/dish
     * 请求方式：POST
     * 请求参数：JSON格式数据 ---> 用什么对象封装  Dish  DishFlavor 都不是！用新的实体类 DishDto;
     * 响应结果【格式统一】：R 对象
     */
    @PostMapping
    public R<String> addDish(@RequestBody DishDto dishDto){
        /**  此时浏览器页面上的菜品表Dish的添加还涉及到菜品口味表Dish_flavor
         * 当前的entity和持久层、数据表交互，dish对于表现层满足不了需求，所以我们新建了DishDTO
         * DishDTO里面只声明了一个categoryName还不够，还需要加上口味,先复制实体类 DishFlavor到entity包下
         * 然后到 DishDTO类中 再声明下DishFlavor口味的属性 private List <DishFlavor> flavors;
         */
        //添加dish表数据
        dishService.save(dishDto);

        //添加dishFlavors表数据,用集合去接收
        List<DishFlavor> flavors = dishDto.getFlavors();

        //判断是否选择了口味
        if (flavors!=null && flavors.size()>0){
            //保存菜品口味数据到菜品口味表dish_flavor，需要注意：DishFlavor中dishID是没有数据的，
            //所以要手动设置
            Long dishId = dishDto.getId(); //菜品的id

            //flavors.for
            for (DishFlavor flavor : flavors) {
                flavor.setDishId(dishId);
                dishService.getById(flavor);
            }

        }
        return R.success("添加成功");

    }
    /**          分页查询菜品数据
     * 请求url地址：/dish/page ?page=1&pageSize=10&name=白菜
     * 请求方式：GET
     * 请求参数：?page=1&pageSize=10&name=白菜
     * 响应结果【格式统一】：R 对象
     */

    @GetMapping("/page")
    public R<Page> queryDishByPage(Integer page,Integer pageSize,String name){

        //目前的dish表中只有category_id,没有category_name（分类名称）
//        Page<Dish> dishPage = new Page<>(page,pageSize);
        /**  dish对象缺少category_name，在表现层创建dishDto对象，将dish里的属性拷贝给dishDto
         * 此时，需要DTO对象，我们现在写的叫entity实体对象和数据表一一对应的，数据表有哪些字段，实体类就有，
         * 而有时候我们表现层和前端、客户、业务层进行交流、交互时，往往实体对象里面的数据满足不了我们的需求(比如现在就没有category_name)
         * entity跟我们持久层的数据表绑定起来的，未来跟持久层交互起来非常方便
         * 此时，可以再封装一个DTO对象 ，跟表现层、业务层、前端进行交互时时用的实体对象，它可以多封装些数据
         *为了不去影响持久层的entity操作，所以新建一个DTO类，新建一个包dto,实体类为DishDTO，专门给表现层使用的
         */
        // 创建Dish分页对象，这个Dish分页对象是用来查询dish菜品分类分页数据的
        Page<Dish> dishPage = new Page<>(page,pageSize);

        //创建条件构造器
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        //设置查询条件
//        wrapper.like(name!=null && name!="",Dish::getName,name);
        //选择StringUtils org.apache.commons.lang 这个依赖（提供了大量的字符串操作的API）
        // 做非空判断，可以利用工具类判断

        wrapper.like(StringUtils.isNotEmpty(name),Dish::getName,name);
        //也可以更具需求添加条件，比如按照发布时间降序
        wrapper.orderByDesc(Dish::getCreateTime);

        dishService.page(dishPage,wrapper);//要加条件，因为参数当中还有个name

//现在有两个分页对象，最终要返回的是DishDTO这个分页对象给前端，因为 dishDTO不仅有Dish菜品种类还有categoryName菜品名称
        Page<DishDto> dishDtoPage = new Page<>();
        //实现 Page<Dish> 和 Page<DishDTO> 对象 之间的属性对拷（拷贝），利用工具类 BeanUtils org.springframework.beans
        BeanUtils.copyProperties(dishPage,dishDtoPage,"records");//记录数
        //现在我们将dishPage里面的属性都给dishDTOPage，但就是不拷"records",因为这两个对象records里面封装的东西不一样
        //但现在 records 没有数据，totals是有值的


        // 使用stream流，借助map接口

        List<DishDto> dishDtoList = dishPage.getRecords().stream().map(dish -> {
            DishDto dishDto = new DishDto();
            //直接用工具类获取
            BeanUtils.copyProperties(dish, dishDto); //拷贝

            //查询菜品分类表，查询当前这道菜的分类名称： select categoryName from category where id=?(dish表中的category_id)
            Category category = categoryService.getById(dish.getCategoryId());//分类
            dishDto.setCategoryName(category.getName()); //设置
            return dishDto;   //返回
        }).collect(Collectors.toList());
        //将处理完毕后的dishDTO集合封装到Page对象中返回
        dishDtoPage.setRecords(dishDtoList);

        //4.返回Page对象
        return R.success(dishDtoPage);
    }

    /**  修改菜品数据： 先查后改   接口1：根据id查询菜品数据，用于回显
     *     根据id查询菜品信息和对应的口味信息
     *         注意点： 前端要返回dishDTO，它不仅要展示待修改的菜品数据，口味也要
     *        根据ID查询菜品信息
     *      最终返回的是DishDTO,封装的也是它
     * 请求url地址：/dish/1504708761831292929
     * 请求方式：GET
     * 请求参数：无
     * 响应结果【格式统一】：R 对象
     */
    @GetMapping("/{id}") //id若不加{}占位符，就是请求路径，加了{id}就是请求参数，比如网页上where id = 几
    public R<DishDto> queryById(@PathVariable  Long id){
        //方法一：
        /**
         * 1. 在DishService接口中扩展getByIdWithFlavor方法
         * 2. 在DishService实现类中实现此方法：
         *         具体逻辑为:
         *          A. 根据ID查询菜品的基本信息
         *          B. 根据菜品的ID查询菜品口味列表数据
         *          C. 组装数据并返回
         * 3. 在DishController中创建get方法
         */
        DishDto dishDto = dishService.getByIdWithFlavor(id);
        return R.success(dishDto);

        //方法二：

        //1.查询dish表
        //  DishDTO dishDto = (DishDTO) dishService.getById(id);

        //2.查询口味表 dish_flavor

    }
    /**      接口二：修改菜品
     *  请求url地址：/dish
     * 请求方式：PUT
     * 请求参数：JSON格式的数据  ，使用DishDto封装,
     * 注意点： 使用DishDto来接收待修改的菜品和口味
     */
    @PutMapping
    public R updateDish(@RequestBody DishDto dishDto){
        /**  1.在DishService接口中扩展方法updateWithFlavor
         *       //更新菜品信息，同时更新对应的口味信息
         *              public void updateWithFlavor(DishDto dishDto);
         *   2.在DishServiceImpl中实现方法updateWithFlavor
         *   3.在DishController中创建update方法
         */
        dishService.updateWithFlavor(dishDto);
        return R.success("修改菜品成功");

    }
    /**  #### 删除菜品接口[和批量删除用的是同一个接口]
     * 请求url地址：/dish    ?ids=1504708761831292929,1504653856504483842
     * 请求方式：DELETE
     * 请求参数：?ids=1504708761831292929,1504653856504483842
     * 响应结果【格式统一】：R 对象
     */
    @DeleteMapping
    public R deleteByIds(@RequestParam List ids){// k=v 格式 ,用list集合接收ids

        //逻辑删除
        dishService.removeByIds(ids);

        return R.success("删除成功");

    }
    /**   接口七：起售/停售 批量起售/批量停售
     * 请求url地址：/dish/status/1  ?ids=1504708761831292929,1504653856504483842,1413384757047271425
     * 请求方式：POST
     * 请求参数：?ids=1504708761831292929,1504653856504483842,1413384757047271425
     * 响应结果【格式统一】：R 对象
     */
    @PostMapping("/status/{status}") //第二个status是变量要用占位符{status}去接收
    public R<DishDto> changStatus(@RequestParam List ids,@PathVariable Integer status){

        // update dish set status = ? where id in (1,2,3)
        LambdaUpdateWrapper<Dish> qw = new LambdaUpdateWrapper<>();
        qw.set(Dish::getStatus,status);// set status = ?
        qw.in(Dish::getId,ids);//  where id in (1,2,3)
        dishService.update(qw);

        return R.success(null);
    }
    /**    新增套餐   根据条件查询对应的菜品数据
     * 在DishController中定义方法list，接收Dish类型的参数：

     ##### 接口4：根据分类id查询该分类下的所有菜品集合[之前写过，但是需要改造！！]
     请求url地址：/dish/list    ?categoryId=1397844263642378242
     请求方式：GET
     请求参数：?categoryId=1397844263642378242
     响应结果【格式统一】：R<List<Dish>> 对象
     *
     * 在查询时，需要根据菜品分类categoryId进行查询，
     * 并且还要限定菜品的状态为起售状态(status为1)，然后对查询的结果进行排序。
     */
    /**
     *  客户端主页面请求此接口
     *          原接口返回结果 R<List<Dish>> 菜品Dish的集合
     *          新接口返回结果 R<List<DishDto>>返回的Dish集合中还需要有菜品的口味数据
     *                     DishDto[既包含菜品数据也包含菜品的口味数据]
     *        完善的功能： 查询并封装当前每一道菜品的口味数据
     */
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        // 1.分页+条件查询    构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());

        queryWrapper.eq(Dish::getStatus,1); //添加条件，查询状态为1（起售状态）的菜品

        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

        //2。查询菜品
        List<Dish> list = dishService.list(queryWrapper);

        //3.查询菜品
        List<DishDto> dishDtoList = list.stream().map((item) -> {
            DishDto dishDTO = new DishDto();
            BeanUtils.copyProperties(item,dishDTO);

            // 3.1 封装分类名称
            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);
            if(category != null){
                String categoryName = category.getName();
                dishDTO.setCategoryName(categoryName);
            }

            //当前菜品的id
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            //SQL:select * from dish_flavor where dish_id = ?
            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            dishDTO.setFlavors(dishFlavorList);

            return dishDTO;
        }).collect(Collectors.toList());

        return R.success(dishDtoList);
    }

}
